﻿/*
Copyright 2009 Matías Fidemraizer (www.matiasfidemraizer.com).

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

using System;
using Comkarl.Architecture.Patterns.MVC;

namespace Comkarl.Architecture.Patterns.DomainModel
{
    /// <summary>
    /// Represents an object living in the business layer which is an actor in the business logic.
    /// </summary>
    /// <typeparam name="TIdentifierName">
    /// The type for the unique business object identifier's name.
    /// </typeparam>
    [Serializable]
    public abstract class DomainObject<TIdentifierName> : PatternInstanceMember<TIdentifierName, MVCInstance<TIdentifierName>>
        where TIdentifierName : IEquatable<TIdentifierName>
    {
        private string title;
        private DateTime dateAdded;
        private DateTime dateModified;

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="id">
        /// The unique identifier for the business object.
        /// </param>
        public DomainObject(DomainObjectIdentifier<TIdentifierName> id)
            : base(id)
        {
            Warmup();
        }

        /// <summary>
        /// Parameterless constructor.
        /// </summary>
        public DomainObject()
            : base(null)
        {
            Warmup();
        }

        /// <summary>
        /// Raised when some current object's property is going to change its value.
        /// </summary>
        public event EventHandler<DomainObjectStateEventArgs> Changing;

        /// <summary>
        /// Raised when some current object's property has changed its value.
        /// </summary>
        public event EventHandler<DomainObjectStateEventArgs> Changed;

        /// <summary>
        /// Gets the unique identifier for the current business object.
        /// </summary>
        new public virtual DomainObjectIdentifier<TIdentifierName> ID
        {
            get { return (DomainObjectIdentifier<TIdentifierName>)base.ID; }
        }

        /// <summary>
        /// Gets or sets the title for the current business object.
        /// </summary>
        public virtual string Title 
        { 
            get 
            { 
                return title; 
            } 
            set
            {
                NotifyChanging("Title");

                title = value;

                NotifyChanged("Title");
            } 
        }

        /// <summary>
        /// Gets or sets the date at which current business object was added in the data store.
        /// </summary>
        public virtual DateTime DateAdded 
        { 
            get 
            { 
                return dateAdded; 
            }
            set
            {
                dateAdded = value;
            }
        }

        /// <summary>
        /// Gets or sets the date at which current business object was modified last time in the data store.
        /// </summary>
        public virtual DateTime DateModified 
        { 
            get 
            { 
                return dateModified; 
            }
            set
            {
                dateModified = value;
            }
        }

        protected void NotifyChanging(string affectedPropertyName)
        {
            if (Changing != null)
            {
                Changing(this, new DomainObjectStateEventArgs(affectedPropertyName));
            }
        }

        protected void NotifyChanged(string affectedPropertyName)
        {
            if (Changed != null)
            {
                Changed(this, new DomainObjectStateEventArgs(affectedPropertyName));
            }
        }

        private void Warmup()
        {
            Changed += new EventHandler<DomainObjectStateEventArgs>(
                delegate(object sender, DomainObjectStateEventArgs e)
                {
                    DateModified = DateTime.Now;
                }
            );
        }
    }
}